package com.rapida.net;

import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Created by mm on 2014/12/31.
 */
public class UDPClient {
	private static final String TAG = "UDPClient";
	private final String broadcast = "255.255.255.255";
	private int port = 2589;
	private String deviceName = "HOST";
	private boolean isHost = false;
	private ArrayList<Host> hosts = new ArrayList<Host>();
	private DatagramSocket dataSocket;
	private static boolean isWork = true;
	private UPDHandler mHandler;
	private HostListener mListener;

	public interface HostListener {
		public void newHost(Host host);

		public void removeHost(Host host);
	}

	public interface UPDHandler {
		public void receive(String ip, DatagramPacket packet, byte[] de);
	}

	public void initUDPClient() {
		isWork = true;
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					dataSocket = new DatagramSocket(port);
				} catch (SocketException e) {
					isWork = false;
					Log.d(TAG, "create DatagramSocket failed");
				}
				byte[] buf = new byte[64];
				DatagramPacket packet = new DatagramPacket(buf, buf.length);
				while (isWork) {
					try {
						dataSocket.receive(packet);
						byte[] data = Arrays.copyOfRange(buf, 0, packet.getLength());
						byte[] de = UDPProtocol.decode(data);
						if (de != null) {
							byte requestType = de[0];
							switch (requestType) {
								// 接收到请求主机消息
								case UDPProtocol.MSG_HOST_REQUEST:
									if (isHost) {
										// 是主机 就返回
										responseHost(packet.getAddress().getHostAddress());
									}
									break;
								// 接收到主机信息
								case UDPProtocol.MSG_HOST_RESPONSE:
									String ip = packet.getAddress().getHostAddress();
									String name = new String(Arrays.copyOfRange(de, 1, de.length), "utf-8");
									Host host = new Host(ip, name);
									addHost(host);
									if (mListener != null) {
										mListener.newHost(host);
									}
									break;
								// 接收到主机退出
								case UDPProtocol.MSG_HOST_QUIT:
									ip = packet.getAddress().getHostAddress();
									name = new String(Arrays.copyOfRange(de, 1, de.length), "utf-8");
									host = new Host(ip, name);
									removeHost(host);
									if (mListener != null) {
										mListener.removeHost(host);
									}
									break;
								default:
									if (mHandler != null) {
										ip = packet.getAddress().getHostAddress();
										mHandler.receive(ip, packet, de);
									}
							}
						}
					} catch (Exception e) {
						Log.d(TAG, "receive DatagramSocket failed");
					}
				}
				if (dataSocket != null) {
					dataSocket.close();
					dataSocket = null;
				}
			}
		}).start();
	}

	public void registerHandler(UPDHandler handler) {
		mHandler = handler;
	}
	public void registerHostListener(HostListener listener) {
		mListener = listener;
	}

	public void setPort(int port) {
		this.port = port;
	}

	private boolean addHost(Host host) {
		boolean r = false;
		synchronized (hosts) {
			if (!hosts.contains(host)) {
				hosts.add(host);
				r = true;
			}
		}
		return r;
	}

	private Host removeHost(Host host) {
		synchronized (hosts) {
			if (hosts.contains(host)) {
				hosts.remove(host);
				return host;
			}
		}
		return null;
	}

	public void startHost() {
		isHost = true;
		responseHost(null);
	}

	public void stopHost() {
		isHost = false;
	}

	public void cleanUPDClient() {
		isWork = false;
		if (dataSocket != null) {
			dataSocket.close();
			dataSocket = null;
		}
	}

	public void responseHost(String ip) {
		Host host = new Host();
		host.setName(deviceName);
		if (ip != null) {
			send(ip, UDPProtocol.responseHost(host));
		}
		broadCast(UDPProtocol.responseHost(host));
	}

	public void broadCastRequestHost() {
		send(broadcast, UDPProtocol.requestHost());
	}

	public ArrayList<Host> getHosts() {
		return hosts;
	}

	private void broadCast(final byte[] bag) {
		new Thread(new Runnable() {
			public void run() {
				try {
					DatagramSocket socket = new DatagramSocket();
					InetAddress address = InetAddress.getByName(broadcast);
					socket.setBroadcast(true);
					DatagramPacket packet = new DatagramPacket(bag, bag.length);
					packet.setAddress(address);
					packet.setPort(port);
					socket.send(packet);
				} catch (Exception e) {
					Log.d("TAG", "broadCast() exception" + e.getMessage());
				}
			}
		}).start();
	}


	public void send(final String ip, final byte[] bag) {
		new Thread(new Runnable() {
			public void run() {
				try {
					DatagramSocket socket = new DatagramSocket();
					InetAddress address = InetAddress.getByName(ip);
					DatagramPacket packet = new DatagramPacket(bag, bag.length);
					packet.setAddress(address);
					packet.setPort(port);
					socket.send(packet);
				} catch (Exception e) {
					Log.d("TAG", "send() exception" + e.getMessage());
				}

			}
		}).start();
	}
}
